use crate::UtilsCommands;
use indicatif::{ProgressBar, ProgressStyle};
use qrcode::QrCode;
use image::Luma;
use std::fs;
use std::path::Path;
use uuid::Uuid;
use chrono::{DateTime, Utc, TimeZone};
use base64::{Engine as _, engine::general_purpose};
use hex;
use urlencoding;

pub fn handle_utils_commands(command: UtilsCommands, verbose: bool) -> Result<(), Box<dyn std::error::Error>> {
    match command {
        UtilsCommands::Uuid { count, format } => {
            generate_uuids(count, &format, verbose)?;
        },
        UtilsCommands::Encode { text, type_ } => {
            encode_text(&text, &type_, verbose)?;
        },
        UtilsCommands::Decode { text, type_ } => {
            decode_text(&text, &type_, verbose)?;
        },
        UtilsCommands::Qr { text, output, size } => {
            generate_qr_code(&text, output.as_deref(), size, verbose)?;
        },
        UtilsCommands::Timestamp { timestamp, format } => {
            handle_timestamp(timestamp, &format, verbose)?;
        },
    }
    Ok(())
}

fn generate_uuids(count: usize, format: &str, verbose: bool) -> Result<(), Box<dyn std::error::Error>> {
    let pb = ProgressBar::new(count as u64);
    pb.set_style(ProgressStyle::default_bar()
        .template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} {msg}")?
        .progress_chars("#>-"));
    
    println!("🆔 生成 UUID:");
    
    for i in 0..count {
        let uuid = Uuid::new_v4();
        let formatted = match format {
            "uuid" => uuid.to_string(),
            "hex" => uuid.as_bytes().iter().map(|b| format!("{:02x}", b)).collect::<String>(),
            "base64" => general_purpose::STANDARD.encode(uuid.as_bytes()),
            _ => uuid.to_string(),
        };
        
        println!("  {}", formatted);
        
        if verbose && i < 5 {
            println!("    版本: {}", uuid.get_version());
            println!("    变体: {}", uuid.get_variant());
        }
        
        pb.inc(1);
        pb.set_message("生成中...");
    }
    
    pb.finish_with_message("✅ 生成完成");
    Ok(())
}

fn encode_text(text: &str, type_: &str, verbose: bool) -> Result<(), Box<dyn std::error::Error>> {
    let encoded = match type_ {
        "base64" => {
            general_purpose::STANDARD.encode(text.as_bytes())
        },
        "hex" => {
            hex::encode(text.as_bytes())
        },
        "url" => {
            urlencoding::encode(text).to_string()
        },
        _ => return Err("不支持的编码类型".into()),
    };
    
    println!("🔤 编码结果:");
    println!("  原始: {}", text);
    println!("  编码: {}", encoded);
    
    if verbose {
        println!("  类型: {}", type_);
        println!("  原始长度: {} 字符", text.len());
        println!("  编码长度: {} 字符", encoded.len());
    }
    
    Ok(())
}

fn decode_text(text: &str, type_: &str, verbose: bool) -> Result<(), Box<dyn std::error::Error>> {
    let decoded = match type_ {
        "base64" => {
            let bytes = general_purpose::STANDARD.decode(text)?;
            String::from_utf8(bytes)?
        },
        "hex" => {
            let bytes = hex::decode(text)?;
            String::from_utf8(bytes)?
        },
        "url" => {
            urlencoding::decode(text)?.to_string()
        },
        _ => return Err("不支持的解码类型".into()),
    };
    
    println!("🔤 解码结果:");
    println!("  编码: {}", text);
    println!("  解码: {}", decoded);
    
    if verbose {
        println!("  类型: {}", type_);
        println!("  编码长度: {} 字符", text.len());
        println!("  解码长度: {} 字符", decoded.len());
    }
    
    Ok(())
}

fn generate_qr_code(text: &str, output: Option<&Path>, size: u32, verbose: bool) -> Result<(), Box<dyn std::error::Error>> {
    let pb = ProgressBar::new_spinner();
    pb.set_message("生成二维码...");
    
    let code = QrCode::new(text)?;
    let image = code.render::<Luma<u8>>()
        .max_dimensions(size, size)
        .build();
    
    match output {
        Some(path) => {
            image.save(path)?;
            pb.finish_with_message("✅ 二维码生成完成");
            println!("📱 二维码已保存到: {}", path.display());
        },
        None => {
            // 在终端中显示二维码
            let string = code.render()
                .light_color(termcolor::Color::White)
                .dark_color(termcolor::Color::Black)
                .build();
            pb.finish_with_message("✅ 二维码生成完成");
            println!("📱 二维码:");
            println!("{}", string);
        }
    }
    
    if verbose {
        println!("  内容: {}", text);
        println!("  大小: {}x{}", size, size);
        println!("  版本: {}", code.version());
        println!("  错误纠正级别: {:?}", code.error_correction_level());
    }
    
    Ok(())
}

fn handle_timestamp(timestamp: Option<i64>, format: &str, verbose: bool) -> Result<(), Box<dyn std::error::Error>> {
    let now = Utc::now();
    let dt = if let Some(ts) = timestamp {
        if ts > 1_000_000_000_000 {
            // 毫秒时间戳
            Utc.timestamp_millis_opt(ts).single().unwrap_or(now)
        } else {
            // 秒时间戳
            Utc.timestamp_opt(ts, 0).single().unwrap_or(now)
        }
    } else {
        now
    };
    
    let formatted = match format {
        "rfc3339" => dt.to_rfc3339(),
        "rfc2822" => dt.to_rfc2822(),
        "iso8601" => dt.to_rfc3339(),
        "unix" => dt.timestamp().to_string(),
        "unix_ms" => dt.timestamp_millis().to_string(),
        "human" => dt.format("%Y-%m-%d %H:%M:%S UTC").to_string(),
        _ => dt.to_rfc3339(),
    };
    
    println!("⏰ 时间戳转换:");
    println!("  时间: {}", formatted);
    
    if verbose {
        println!("  原始时间戳: {}", dt.timestamp());
        println!("  毫秒时间戳: {}", dt.timestamp_millis());
        println!("  格式: {}", format);
        println!("  时区: UTC");
    }
    
    Ok(())
}

// 其他实用工具函数
pub fn format_file_size(bytes: u64) -> String {
    const UNITS: &[&str] = &["B", "KB", "MB", "GB", "TB", "PB"];
    let mut size = bytes as f64;
    let mut unit_index = 0;
    
    while size >= 1024.0 && unit_index < UNITS.len() - 1 {
        size /= 1024.0;
        unit_index += 1;
    }
    
    format!("{:.2} {}", size, UNITS[unit_index])
}

pub fn format_duration(duration: std::time::Duration) -> String {
    let total_seconds = duration.as_secs();
    let hours = total_seconds / 3600;
    let minutes = (total_seconds % 3600) / 60;
    let seconds = total_seconds % 60;
    
    if hours > 0 {
        format!("{}h {}m {}s", hours, minutes, seconds)
    } else if minutes > 0 {
        format!("{}m {}s", minutes, seconds)
    } else {
        format!("{}s", seconds)
    }
}

pub fn calculate_entropy(text: &str) -> f64 {
    let mut counts = std::collections::HashMap::new();
    for ch in text.chars() {
        *counts.entry(ch).or_insert(0) += 1;
    }
    
    let length = text.len() as f64;
    counts.values()
        .map(|&count| {
            let p = count as f64 / length;
            -p * p.log2()
        })
        .sum()
}

pub fn validate_email(email: &str) -> bool {
    use regex::Regex;
    let re = Regex::new(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$").unwrap();
    re.is_match(email)
}

pub fn validate_url(url: &str) -> bool {
    use regex::Regex;
    let re = Regex::new(r"^https?://[^\s/$.?#].[^\s]*$").unwrap();
    re.is_match(url)
}

pub fn generate_random_string(length: usize, charset: &str) -> String {
    use rand::Rng;
    let mut rng = rand::thread_rng();
    (0..length)
        .map(|_| charset.chars().nth(rng.gen_range(0..charset.len())).unwrap())
        .collect()
}

pub fn calculate_checksum(data: &[u8]) -> u32 {
    use crc32fast::Hasher;
    let mut hasher = Hasher::new();
    hasher.update(data);
    hasher.finalize()
}

pub fn compress_data(data: &[u8]) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
    use flate2::write::GzEncoder;
    use flate2::Compression;
    use std::io::Write;
    
    let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
    encoder.write_all(data)?;
    Ok(encoder.finish()?)
}

pub fn decompress_data(data: &[u8]) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
    use flate2::read::GzDecoder;
    use std::io::Read;
    
    let mut decoder = GzDecoder::new(data);
    let mut decompressed = Vec::new();
    decoder.read_to_end(&mut decompressed)?;
    Ok(decompressed)
}

